home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir37 / ms_sh23s.zip / SRC / SH11.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  23KB  |  1,013 lines

  1. /*
  2.  * MS-DOS SHELL - Maths Evaluation Functions
  3.  *
  4.  * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Paul Falstad
  5.  *
  6.  * This code is based on (in part) the shell program written by Paul Falstad
  7.  * and is subject to the following copyright restrictions:
  8.  *
  9.  * 1.  Redistribution and use in source and binary forms are permitted
  10.  *     provided that the above copyright notice is duplicated in the
  11.  *     source form and the copyright notice in file sh6.c is displayed
  12.  *     on entry to the program.
  13.  *
  14.  * 2.  The sources (or parts thereof) or objects generated from the sources
  15.  *     (or parts of sources) cannot be sold under any circumstances.
  16.  *
  17.  * This source is based on the math.c (mathematical expression evaluation) from
  18.  * the Z shell.  Z Shell is free software, under the GNU license.  This
  19.  * code is included in this program under the provisions of paragraph 8 of
  20.  * GNU GENERAL PUBLIC LICENSE, Version 1, February 1989.  I contacted Paul
  21.  * via E-Mail, and he is happy to allow the source to be included in this
  22.  * program.
  23.  *
  24.  *    $Header: /usr/users/istewart/shell/sh2.3/Release/RCS/sh11.c,v 2.10 1994/08/25 20:49:11 istewart Exp $
  25.  *
  26.  *    $Log: sh11.c,v $
  27.  *    Revision 2.10  1994/08/25  20:49:11  istewart
  28.  *    MS Shell 2.3 Release
  29.  *
  30.  *    Revision 2.9  1994/02/01  10:25:20  istewart
  31.  *    Release 2.3 Beta 2, including first NT port
  32.  *
  33.  *    Revision 2.8  1993/11/09  10:39:49  istewart
  34.  *    Beta 226 checking
  35.  *
  36.  *    Revision 2.7  1993/07/02  10:21:35  istewart
  37.  *    224 Beta fixes
  38.  *
  39.  *    Revision 2.7  1993/07/02  10:21:35  istewart
  40.  *    224 Beta fixes
  41.  *
  42.  *    Revision 2.6  1993/06/14  11:01:44  istewart
  43.  *    More changes for 223 beta
  44.  *
  45.  *    Revision 2.5  1993/06/02  09:52:35  istewart
  46.  *    Beta 223 Updates - see Notes file
  47.  *
  48.  *    Revision 2.4  1993/02/16  16:03:15  istewart
  49.  *    Beta 2.22 Release
  50.  *
  51.  *    Revision 2.3  1993/01/26  18:35:09  istewart
  52.  *    Release 2.2 beta 0
  53.  *
  54.  *    Revision 2.2  1992/11/06  10:03:44  istewart
  55.  *    214 Beta test updates
  56.  *
  57.  *    Revision 2.1  1992/07/10  10:52:48  istewart
  58.  *    211 Beta updates
  59.  *
  60.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  61.  *    MS-Shell 2.0 Baseline release
  62.  *
  63.  */
  64.  
  65. #include <sys/types.h>
  66. #include <sys/stat.h>
  67. #include <stdio.h>
  68. #include <signal.h>
  69. #include <setjmp.h>
  70. #include <ctype.h>
  71. #include <string.h>
  72. #include <unistd.h>
  73. #include <stdlib.h>
  74. #include <limits.h>
  75. #include "sh.h"
  76.  
  77. #define STACK_SIZE    100        /* Stack size            */
  78. #define MAX_PRECEDENCE    15
  79. #define MAX_VARIABLES    32        /* Number of user variables    */
  80.  
  81. /*
  82.  * Some macros
  83.  */
  84.  
  85. #define POP_2_VALUES()        b = stack[StackPointer--].val;    \
  86.                   a = stack[StackPointer--].val;
  87.  
  88. #define PUSH_VALUE_ON_STACK(X)    PushOnToStack ((long)(X), -1);
  89. #define SET_VALUE_ON_STACK(X)    PushOnToStack (SetVariableValue    \
  90.                         (lv, (long)(X)), lv);
  91.  
  92. /* the value stack */
  93.  
  94. static int    LastToken;        /* Last token            */
  95. static int    StackPointer = -1;    /* Stack pointer        */
  96.  
  97. static struct MathsStack {
  98.     int        lval;
  99.     long    val;
  100. } stack[STACK_SIZE];
  101.  
  102. static int    NumberOfVariables = 0;        /* Number of variables    */
  103. static char    *ListOfVariableNames[MAX_VARIABLES];
  104. static char    *CStringp;            /* Current position    */
  105. static long    YYLongValue;
  106. static int    YYIntValue;
  107. static int    JustParsing = 0;        /* Nonzero means we are    */
  108.                         /* not evaluating, just    */
  109.                         /* parsing        */
  110. static bool    RecogniseUnaryOperator = TRUE;    /* TRUE means recognize    */
  111.                         /* unary plus, minus,    */
  112.                         /* etc.            */
  113.  
  114. /*
  115.  * LEFT_RIGHT_A = left-to-right associativity
  116.  * RIGHT_LEFT_A = right-to-left associativity
  117.  * BOOL_A = short-circuiting boolean
  118.  */
  119.  
  120. #define LEFT_RIGHT_A            0
  121. #define RIGHT_LEFT_A            1
  122. #define BOOL_A                2
  123.  
  124. #define OP_OPEN_PAR            0
  125. #define OP_CLOSE_PAR            1
  126. #define OP_NOT                2
  127. #define OP_COMPLEMENT            3
  128. #define OP_POST_PLUS            4
  129. #define OP_POST_MINUS            5
  130. #define OP_UNARY_PLUS            6
  131. #define OP_UNARY_MINUS            7
  132. #define OP_BINARY_AND_EQUALS        8
  133. #define OP_BINARY_XOR_EQUALS        9
  134. #define OP_BINARY_OR_EQUALS        10
  135. #define OP_MULTIPLY            11
  136. #define OP_DIVIDE            12
  137. #define OP_MODULUS            13
  138. #define OP_PLUS                14
  139. #define OP_MINUS            15
  140. #define OP_SHIFT_LEFT            16
  141. #define OP_SHIFT_RIGHT            17
  142. #define OP_LESS                18
  143. #define OP_LESS_EQUALS            19
  144. #define OP_GREATER            20
  145. #define OP_GREATER_EQUALS        21
  146. #define OP_EQUALS            22
  147. #define OP_NOT_EQUALS            23
  148. #define OP_LOGICAL_AND_EQUALS        24
  149. #define OP_LOGICAL_OR_EQUALS        25
  150. #define OP_LOGICAL_XOR_EQUALS        26
  151. #define OP_QUESTION_MARK        27
  152. #define OP_COLON            28
  153. #define OP_SET                29
  154. #define OP_PLUS_EQUAL            30
  155. #define OP_MINUS_EQUAL            31
  156. #define OP_MULTIPLY_EQUAL        32
  157. #define OP_DIVIDE_EQUAL            33
  158. #define OP_MODULUS_EQUAL        34
  159. #define OP_BINARY_AND_SET        35
  160. #define OP_BINARY_XOR_SET        36
  161. #define OP_BINARY_OR_SET        37
  162. #define OP_SHIFT_LEFT_EQUAL        38
  163. #define OP_SHIFT_RIGHT_EQUAL        39
  164. #define OP_LOGICAL_AND_SET        40
  165. #define OP_LOGICAL_OR_SET        41
  166. #define OP_LOGICAL_XOR_SET        42
  167. #define OP_COMMA            43
  168. #define OP_END_OF_INPUT            44
  169. #define OP_PRE_PLUS            45
  170. #define OP_PRE_MINUS            46
  171. #define OP_NUMERIC_VALUE        47
  172. #define OP_VARIABLE            48
  173. #define MAX_OPERATORS            49
  174.  
  175. /* precedences */
  176.  
  177. static struct Operators {
  178.     int        Precedences;        /* Operator Precedences        */
  179.     int        Type;            /* Operator Association        */
  180. } Operators [MAX_OPERATORS] = {
  181.     {   1,    LEFT_RIGHT_A },        /* 0 - (            */
  182.     { 137,    LEFT_RIGHT_A },        /* 1 - )            */
  183.     {   2,    RIGHT_LEFT_A },        /* 2 - !            */
  184.     {   2,    RIGHT_LEFT_A },        /* 3 - ~            */
  185.     {   2,    RIGHT_LEFT_A },        /* 4 - x++            */
  186.     {   2,    RIGHT_LEFT_A },        /* 5 - x--            */
  187.     {   2,    RIGHT_LEFT_A },        /* 6 - +            */
  188.     {   2,    RIGHT_LEFT_A },        /* 7 - -            */
  189.     {   4,    LEFT_RIGHT_A },        /* 8 - &            */
  190.     {   5,    LEFT_RIGHT_A },        /* 9 - ^            */
  191.     {   6,    LEFT_RIGHT_A },        /* 10 - |            */
  192.     {   7,    LEFT_RIGHT_A },        /* 11 - *            */
  193.     {   7,    LEFT_RIGHT_A },        /* 12 - /            */
  194.     {   7,    LEFT_RIGHT_A },        /* 13 - %            */
  195.     {   8,    LEFT_RIGHT_A },        /* 14 - +            */
  196.     {   8,    LEFT_RIGHT_A },        /* 15 - -            */
  197.     {   3,    LEFT_RIGHT_A },        /* 16 - <            */
  198.     {   3,    LEFT_RIGHT_A },        /* 17 - >            */
  199.     {   9,    LEFT_RIGHT_A },        /* 18 - < (less than)        */
  200.     {   9,    LEFT_RIGHT_A },        /* 19 - <= (less than equal)    */
  201.     {   9,    LEFT_RIGHT_A },        /* 20 - > (greater than)    */
  202.     {   9,    LEFT_RIGHT_A },        /* 21 - >= (greater than equal) */
  203.     {  10,    LEFT_RIGHT_A },        /* 22 - ==            */
  204.     {  10,    LEFT_RIGHT_A },        /* 23 - !=            */
  205.     {  11,    BOOL_A },        /* 24 - &&            */
  206.     {  12,    BOOL_A },        /* 25 - ||            */
  207.     {  12,    LEFT_RIGHT_A },        /* 26 - ^^            */
  208.     {  13,    RIGHT_LEFT_A },        /* 27 - ?            */
  209.     {  13,    RIGHT_LEFT_A },        /* 28 - :            */
  210.     {  14,    RIGHT_LEFT_A },        /* 29 - =             */
  211.     {  14,    RIGHT_LEFT_A },        /* 30 - +=            */
  212.     {  14,    RIGHT_LEFT_A },        /* 31 - -=            */
  213.     {  14,    RIGHT_LEFT_A },        /* 32 - *=            */
  214.     {  14,    RIGHT_LEFT_A },        /* 33 - /=            */
  215.     {  14,    RIGHT_LEFT_A },        /* 34 - %=            */
  216.     {  14,    RIGHT_LEFT_A },        /* 35 - &=            */
  217.     {  14,    RIGHT_LEFT_A },        /* 36 - ^=            */
  218.     {  14,    RIGHT_LEFT_A },        /* 37 - |=            */
  219.     {  14,    RIGHT_LEFT_A },        /* 38 - <=            */
  220.     {  14,    RIGHT_LEFT_A },        /* 39 - >=            */
  221.     {  14,    BOOL_A },        /* 40 - &&=            */
  222.     {  14,    BOOL_A },        /* 41 - ||=            */
  223.     {  14,    RIGHT_LEFT_A },        /* 42 - ^^=            */
  224.     {  15,    RIGHT_LEFT_A },        /* 43 - ,            */
  225.     { 200,    RIGHT_LEFT_A },        /* 44 - End of input        */
  226.     {   2,    RIGHT_LEFT_A },        /* 45 - ++x            */
  227.     {   2,    RIGHT_LEFT_A },        /* 46 - --x            */
  228.     {   0,    LEFT_RIGHT_A },        /* 47 - Numeric value        */
  229.     {   0,    LEFT_RIGHT_A }        /* 48 - Variable        */
  230. };
  231.  
  232.  
  233.  
  234. /*
  235.  * Functions
  236.  */
  237.  
  238. static void F_LOCAL    PushOnToStack (long, int);
  239. static long F_LOCAL    SetVariableValue (int, long);
  240. static bool F_LOCAL    CheckNotZero (long);
  241. static void F_LOCAL    ProcessOperator (int);
  242. static void F_LOCAL    ProcessBinaryOperator (int);
  243. static void F_LOCAL    ParseMathsExpression (int);
  244. static int F_LOCAL    MathsLexicalAnalyser (void);
  245. static int F_LOCAL    DecideSingleOperator (int, int);
  246. static int F_LOCAL    DecideDoubleOperator (char, int, int, int, int);
  247. static int F_LOCAL    DecideSignOperator (char, int, int, int, int, int);
  248. static char * F_LOCAL    ExtractNameAndIndex (int, int *);
  249.  
  250. /*
  251.  * Analyse the string
  252.  */
  253.  
  254. static int F_LOCAL MathsLexicalAnalyser (void)
  255. {
  256.     while (TRUE)
  257.     {
  258.     switch (*(CStringp++))
  259.     {
  260.         case '+':
  261.         return DecideSignOperator ('+', OP_PRE_PLUS,
  262.                         OP_POST_PLUS,
  263.                         OP_PLUS_EQUAL,
  264.                         OP_UNARY_PLUS,
  265.                         OP_PLUS);
  266.  
  267.         case '-':
  268.         return DecideSignOperator ('+', OP_PRE_MINUS,
  269.                         OP_POST_MINUS,
  270.                         OP_MINUS_EQUAL,
  271.                         OP_UNARY_MINUS,
  272.                         OP_MINUS);
  273.  
  274.         case CHAR_OPEN_PARATHENSIS:
  275.         RecogniseUnaryOperator = TRUE;
  276.         return OP_OPEN_PAR;
  277.  
  278.         case CHAR_CLOSE_PARATHENSIS:
  279.         return OP_CLOSE_PAR;
  280.  
  281.         case '!':
  282.         if (*CStringp == '=')
  283.         {
  284.             RecogniseUnaryOperator = TRUE;
  285.             CStringp++;
  286.             return OP_NOT_EQUALS;
  287.         }
  288.  
  289.         return OP_NOT;
  290.  
  291.         case CHAR_TILDE:
  292.         return OP_COMPLEMENT;
  293.  
  294.         case '&':
  295.         return DecideDoubleOperator ('&', OP_LOGICAL_AND_SET,
  296.                           OP_BINARY_AND_SET,
  297.                           OP_LOGICAL_AND_EQUALS,
  298.                           OP_BINARY_AND_EQUALS);
  299.  
  300.         case '|':
  301.         return DecideDoubleOperator ('|', OP_LOGICAL_OR_SET,
  302.                           OP_BINARY_OR_SET,
  303.                           OP_LOGICAL_OR_EQUALS,
  304.                           OP_BINARY_OR_EQUALS);
  305.  
  306.         case CHAR_XOR:
  307.         return DecideDoubleOperator (CHAR_XOR, OP_LOGICAL_XOR_SET,
  308.                           OP_BINARY_XOR_SET,
  309.                           OP_LOGICAL_XOR_EQUALS,
  310.                           OP_BINARY_XOR_EQUALS);
  311.  
  312.         case '*':
  313.         return DecideSingleOperator (OP_MULTIPLY_EQUAL, OP_MULTIPLY);
  314.  
  315.         case '/':
  316.         return DecideSingleOperator (OP_DIVIDE_EQUAL, OP_DIVIDE);
  317.  
  318.         case '%':
  319.         return DecideSingleOperator (OP_MODULUS_EQUAL, OP_MODULUS);
  320.  
  321.         case '<':
  322.         return DecideDoubleOperator ('<', OP_SHIFT_LEFT_EQUAL,
  323.                           OP_LESS_EQUALS,
  324.                           OP_SHIFT_LEFT,
  325.                           OP_LESS);
  326.  
  327.         case '>':
  328.         return DecideDoubleOperator ('>', OP_SHIFT_RIGHT_EQUAL,
  329.                           OP_GREATER_EQUALS,
  330.                           OP_SHIFT_RIGHT,
  331.                           OP_GREATER);
  332.  
  333.         case CHAR_ASSIGN:
  334.         return DecideSingleOperator (OP_EQUALS, OP_SET);
  335.  
  336.         case '?':
  337.         RecogniseUnaryOperator = TRUE;
  338.         return OP_QUESTION_MARK;
  339.  
  340.         case ':':
  341.         RecogniseUnaryOperator = TRUE;
  342.         return OP_COLON;
  343.  
  344.         case ',':
  345.         RecogniseUnaryOperator = TRUE;
  346.         return OP_COMMA;
  347.  
  348.         case 0:
  349.         RecogniseUnaryOperator = TRUE;
  350.         CStringp--;
  351.         return OP_END_OF_INPUT;
  352.  
  353.         default:
  354.         if (isspace (*(CStringp - 1)))
  355.             break;
  356.  
  357. /* Check for a numeric value */
  358.  
  359.         if (isdigit (*--CStringp))
  360.         {
  361.             char    *End;
  362.             int        base = 10;
  363.  
  364.             RecogniseUnaryOperator = FALSE;
  365.  
  366. /* Which format are we in? base#number or number.  Base is a decimal number
  367.  * so we can check for a decimal base and look at the end character to see
  368.  * if it was a # sign.  If it was, this is a base#number.  Otherwise, its
  369.  * just a number
  370.  */
  371.  
  372.             strtol (CStringp, &End, 10);
  373.  
  374.             if (*End == '#')
  375.             {
  376.             LastNumberBase = (int)strtol (CStringp, &CStringp, 10);
  377.             base = LastNumberBase;
  378.             CStringp++;
  379.             }
  380.  
  381.             YYLongValue = strtol (CStringp, &CStringp, base);
  382.             return OP_NUMERIC_VALUE;
  383.         }
  384.  
  385. /* Check for a variable */
  386.  
  387.         if (IS_VariableFC ((int)*CStringp))
  388.         {
  389.             char    *p, q;
  390.             char    *eb;
  391.  
  392.             p = CStringp;
  393.  
  394.             if (NumberOfVariables == MAX_VARIABLES)
  395.             {
  396.             ShellErrorMessage ("too many identifiers");
  397.             ExpansionErrorDetected = TRUE;
  398.             return OP_END_OF_INPUT;
  399.             }
  400.  
  401.             RecogniseUnaryOperator = FALSE;
  402.  
  403.             while (IS_VariableSC ((int)(*++CStringp)))
  404.             continue;
  405.  
  406. /* Save the variable name.  Check for array index and skip over. */
  407.  
  408.             if ((*CStringp == CHAR_OPEN_BRACKETS) &&
  409.             ((eb = strchr (CStringp,
  410.                        CHAR_CLOSE_BRACKETS)) != (char *)NULL))
  411.             CStringp = eb + 1;
  412.  
  413. /* Save the string */
  414.  
  415.             q = *CStringp;
  416.             *CStringp = 0;
  417.             ListOfVariableNames[YYIntValue = NumberOfVariables++] =
  418.                     StringCopy (p);
  419.             *CStringp = q;
  420.             return OP_VARIABLE;
  421.         }
  422.  
  423.         return OP_END_OF_INPUT;
  424.     }
  425.     }
  426. }
  427.  
  428. /*
  429.  * Stick variable on the stack
  430.  */
  431.  
  432. static void F_LOCAL PushOnToStack (long val, int lval)
  433. {
  434.     if (StackPointer == STACK_SIZE - 1)
  435.     {
  436.     ShellErrorMessage ("stack overflow");
  437.     ExpansionErrorDetected = TRUE;
  438.     }
  439.  
  440.     else
  441.     StackPointer++;
  442.  
  443.     stack[StackPointer].val = val;
  444.     stack[StackPointer].lval = lval;
  445. }
  446.  
  447. /*
  448.  * Get a variable value
  449.  */
  450.  
  451. static long F_LOCAL SetVariableValue (int s, long v)
  452. {
  453.     char    *vn;
  454.     int        index;
  455.  
  456.     if (s == -1 || s >= NumberOfVariables)
  457.     {
  458.     ExpansionErrorDetected = TRUE;
  459.     ShellErrorMessage ("lvalue required");
  460.     return 0;
  461.     }
  462.  
  463.     if (JustParsing)
  464.     return v;
  465.  
  466.     vn = ExtractNameAndIndex (s, &index);
  467.     SetVariableArrayFromNumeric (vn, index, v);
  468.     return v;
  469. }
  470.  
  471. /*
  472.  * Check for Division by zero
  473.  */
  474.  
  475. static bool F_LOCAL CheckNotZero (long a)
  476. {
  477.     if (a)
  478.     return TRUE;
  479.  
  480.     ShellErrorMessage ("division by zero");
  481.     ExpansionErrorDetected = TRUE;
  482.     return FALSE;
  483. }
  484.  
  485. /*
  486.  * Process operator
  487.  */
  488.  
  489. static void F_LOCAL ProcessOperator (int what)
  490. {
  491.     long    a, b, c;
  492.     int        lv;
  493.  
  494.     if (StackPointer < 0)
  495.     {
  496.     ShellErrorMessage ("bad math expression - stack empty");
  497.     ExpansionErrorDetected = TRUE;
  498.     return;
  499.     }
  500.  
  501.     switch (what)
  502.     {
  503.     case OP_NOT:
  504.         stack[StackPointer].val = !stack[StackPointer].val;
  505.         stack[StackPointer].lval= -1;
  506.         break;
  507.  
  508.     case OP_COMPLEMENT:
  509.         stack[StackPointer].val = ~stack[StackPointer].val;
  510.         stack[StackPointer].lval= -1;
  511.         break;
  512.  
  513.     case OP_POST_PLUS:
  514.         SetVariableValue (stack[StackPointer].lval,
  515.                    stack[StackPointer].val + 1);
  516.         break;
  517.  
  518.     case OP_POST_MINUS:
  519.         SetVariableValue (stack[StackPointer].lval,
  520.                    stack[StackPointer].val - 1);
  521.         break;
  522.  
  523.     case OP_UNARY_PLUS:
  524.         stack[StackPointer].lval= -1;
  525.         break;
  526.  
  527.     case OP_UNARY_MINUS:
  528.         stack[StackPointer].val = -stack[StackPointer].val;
  529.         stack[StackPointer].lval= -1;
  530.         break;
  531.  
  532.     case OP_BINARY_AND_EQUALS:
  533.         POP_2_VALUES ();
  534.         PUSH_VALUE_ON_STACK (a & b);
  535.         break;
  536.  
  537.     case OP_BINARY_XOR_EQUALS:
  538.         POP_2_VALUES ();
  539.         PUSH_VALUE_ON_STACK (a ^ b);
  540.         break;
  541.  
  542.     case OP_BINARY_OR_EQUALS:
  543.         POP_2_VALUES ();
  544.         PUSH_VALUE_ON_STACK (a | b);
  545.         break;
  546.  
  547.     case OP_MULTIPLY:
  548.         POP_2_VALUES ();
  549.         PUSH_VALUE_ON_STACK (a * b);
  550.         break;
  551.  
  552.     case OP_DIVIDE:
  553.         POP_2_VALUES ();
  554.  
  555.         if (CheckNotZero (b))
  556.          PUSH_VALUE_ON_STACK (a / b);
  557.  
  558.         break;
  559.  
  560.     case OP_MODULUS:
  561.         POP_2_VALUES ();
  562.  
  563.         if (CheckNotZero (b))
  564.         PUSH_VALUE_ON_STACK (a % b);
  565.  
  566.         break;
  567.  
  568.     case OP_PLUS:
  569.         POP_2_VALUES ();
  570.         PUSH_VALUE_ON_STACK (a + b);
  571.         break;
  572.  
  573.     case OP_MINUS:
  574.         POP_2_VALUES ();
  575.         PUSH_VALUE_ON_STACK (a - b);
  576.         break;
  577.  
  578.     case OP_SHIFT_LEFT:
  579.         POP_2_VALUES ();
  580.         PUSH_VALUE_ON_STACK (a  <<  b);
  581.         break;
  582.  
  583.     case OP_SHIFT_RIGHT:
  584.         POP_2_VALUES ();
  585.         PUSH_VALUE_ON_STACK (a >> b);
  586.         break;
  587.  
  588.     case OP_LESS:
  589.         POP_2_VALUES ();
  590.         PUSH_VALUE_ON_STACK (a < b);
  591.         break;
  592.  
  593.     case OP_LESS_EQUALS:
  594.         POP_2_VALUES ();
  595.         PUSH_VALUE_ON_STACK (a <= b);
  596.         break;
  597.  
  598.     case OP_GREATER:
  599.         POP_2_VALUES ();
  600.         PUSH_VALUE_ON_STACK (a > b);
  601.         break;
  602.  
  603.     case OP_GREATER_EQUALS:
  604.         POP_2_VALUES ();
  605.         PUSH_VALUE_ON_STACK (a >= b);
  606.         break;
  607.  
  608.     case OP_EQUALS:
  609.         POP_2_VALUES ();
  610.         PUSH_VALUE_ON_STACK (a == b);
  611.         break;
  612.  
  613.     case OP_NOT_EQUALS:
  614.         POP_2_VALUES ();
  615.         PUSH_VALUE_ON_STACK (a != b);
  616.         break;
  617.  
  618.     case OP_LOGICAL_AND_EQUALS:
  619.         POP_2_VALUES ();
  620.         PUSH_VALUE_ON_STACK (a && b);
  621.         break;
  622.  
  623.     case OP_LOGICAL_OR_EQUALS:
  624.         POP_2_VALUES ();
  625.         PUSH_VALUE_ON_STACK (a || b);
  626.         break;
  627.  
  628.     case OP_LOGICAL_XOR_EQUALS:
  629.         POP_2_VALUES ();
  630.         PUSH_VALUE_ON_STACK ((a && !b) || (!a && b));
  631.         break;
  632.  
  633.     case OP_QUESTION_MARK:
  634.         c = stack[StackPointer--].val;
  635.         POP_2_VALUES ();
  636.  
  637.         PUSH_VALUE_ON_STACK ((a) ? b : c);
  638.         break;
  639.  
  640.     case OP_COLON:
  641.         break;
  642.  
  643.     case OP_SET:
  644.         POP_2_VALUES ();
  645.         lv = stack[StackPointer + 1].lval;
  646.         SET_VALUE_ON_STACK (b);
  647.         break;
  648.  
  649.     case OP_PLUS_EQUAL:
  650.         POP_2_VALUES ();
  651.         lv = stack[StackPointer + 1].lval;
  652.         SET_VALUE_ON_STACK (a + b);
  653.         break;
  654.  
  655.     case OP_MINUS_EQUAL:
  656.         POP_2_VALUES ();
  657.         lv = stack[StackPointer + 1].lval;
  658.         SET_VALUE_ON_STACK (a - b);
  659.         break;
  660.  
  661.     case OP_MULTIPLY_EQUAL:
  662.         POP_2_VALUES ();
  663.         lv = stack[StackPointer + 1].lval;
  664.         SET_VALUE_ON_STACK (a * b);
  665.         break;
  666.  
  667.     case OP_DIVIDE_EQUAL:
  668.         POP_2_VALUES ();
  669.         lv = stack[StackPointer + 1].lval;
  670.  
  671.         if (CheckNotZero (b))
  672.         SET_VALUE_ON_STACK (a / b);
  673.  
  674.         break;
  675.  
  676.     case OP_MODULUS_EQUAL:
  677.         POP_2_VALUES ();
  678.         lv = stack[StackPointer + 1].lval;
  679.  
  680.         if (CheckNotZero (b))
  681.          SET_VALUE_ON_STACK (a % b);
  682.  
  683.         break;
  684.  
  685.     case OP_BINARY_AND_SET:
  686.         POP_2_VALUES ();
  687.         lv = stack[StackPointer + 1].lval;
  688.         SET_VALUE_ON_STACK (a & b);
  689.         break;
  690.  
  691.     case OP_BINARY_XOR_SET:
  692.         POP_2_VALUES ();
  693.         lv = stack[StackPointer + 1].lval;
  694.         SET_VALUE_ON_STACK (a ^ b);
  695.         break;
  696.  
  697.     case OP_BINARY_OR_SET:
  698.         POP_2_VALUES ();
  699.         lv = stack[StackPointer + 1].lval;
  700.         SET_VALUE_ON_STACK (a | b);
  701.         break;
  702.  
  703.     case OP_SHIFT_LEFT_EQUAL:
  704.         POP_2_VALUES ();
  705.         lv = stack[StackPointer + 1].lval;
  706.         SET_VALUE_ON_STACK (a << b);
  707.         break;
  708.  
  709.     case OP_SHIFT_RIGHT_EQUAL:
  710.         POP_2_VALUES ();
  711.         lv = stack[StackPointer + 1].lval;
  712.         SET_VALUE_ON_STACK (a >> b);
  713.         break;
  714.  
  715.     case OP_LOGICAL_AND_SET:
  716.         POP_2_VALUES ();
  717.         lv = stack[StackPointer + 1].lval;
  718.         SET_VALUE_ON_STACK (a && b);
  719.         break;
  720.  
  721.     case OP_LOGICAL_OR_SET:
  722.         POP_2_VALUES ();
  723.         lv = stack[StackPointer + 1].lval;
  724.         SET_VALUE_ON_STACK (a || b);
  725.         break;
  726.  
  727.     case OP_LOGICAL_XOR_SET:
  728.         POP_2_VALUES ();
  729.         lv = stack[StackPointer + 1].lval;
  730.         SET_VALUE_ON_STACK ((a && !b) || (!a && b));
  731.         break;
  732.  
  733.     case OP_COMMA:
  734.         POP_2_VALUES ();
  735.         PUSH_VALUE_ON_STACK (b);
  736.         break;
  737.  
  738.     case OP_PRE_PLUS:
  739.         stack[StackPointer].val =
  740.         SetVariableValue (stack[StackPointer].lval,
  741.                   stack[StackPointer].val + 1);
  742.         break;
  743.  
  744.     case OP_PRE_MINUS:
  745.         stack[StackPointer].val =
  746.         SetVariableValue (stack[StackPointer].lval,
  747.                   stack[StackPointer].val - 1);
  748.         break;
  749.  
  750.     default:
  751.         ShellErrorMessage ("out of integers");
  752.         ExpansionErrorDetected = TRUE;
  753.         return;
  754.     }
  755. }
  756.  
  757. /*
  758.  * Handle binary operators
  759.  */
  760.  
  761. static void F_LOCAL ProcessBinaryOperator (int tk)
  762. {
  763.     switch (tk)
  764.     {
  765.     case OP_LOGICAL_AND_EQUALS:
  766.     case OP_LOGICAL_AND_SET:
  767.         if (!stack[StackPointer].val)
  768.         JustParsing++;
  769.  
  770.         break;
  771.  
  772.     case OP_LOGICAL_OR_EQUALS:
  773.     case OP_LOGICAL_OR_SET:
  774.         if (stack[StackPointer].val)
  775.         JustParsing++;
  776.  
  777.         break;
  778.     }
  779. }
  780.  
  781. /*
  782.  * Common processing
  783.  */
  784.  
  785. long EvaluateMathsExpression (char *s)
  786. {
  787.     int        i;
  788.  
  789.     for (i = 0; i != MAX_VARIABLES; i++)
  790.     ListOfVariableNames[i] = (char *)NULL;
  791.  
  792.     LastNumberBase = -1;        /* Reset base            */
  793.     NumberOfVariables = 0;
  794.     CStringp = s;
  795.     StackPointer = -1;
  796.     RecogniseUnaryOperator = TRUE;
  797.     ParseMathsExpression (MAX_PRECEDENCE);
  798.  
  799.     if (StackPointer)
  800.     {
  801.     ShellErrorMessage ("bad math expression - unbalanced stack");
  802.     ExpansionErrorDetected = TRUE;
  803.     }
  804.  
  805.     if (*CStringp)
  806.     {
  807.     ShellErrorMessage ("bad math expression - illegal character: %c",
  808.                *CStringp);
  809.     ExpansionErrorDetected = TRUE;
  810.     }
  811.  
  812.     for (i = 0; i != NumberOfVariables; i++)
  813.     ReleaseMemoryCell ((void *)ListOfVariableNames[i]);
  814.  
  815.     return stack[0].val;
  816. }
  817.  
  818. /*
  819.  * operator-precedence parse the string and execute
  820.  */
  821.  
  822. static void F_LOCAL ParseMathsExpression (int pc)
  823. {
  824.     char    *vn;
  825.     int        index;
  826.  
  827.     LastToken = MathsLexicalAnalyser ();
  828.  
  829.     while (Operators[LastToken].Precedences <= pc)
  830.     {
  831.     if (LastToken == OP_NUMERIC_VALUE)
  832.         PushOnToStack (YYLongValue, -1);
  833.  
  834.     else if (LastToken == OP_VARIABLE)
  835.     {
  836.         vn = ExtractNameAndIndex (YYIntValue, &index);
  837.         PushOnToStack (GetVariableArrayAsNumeric (vn, index), YYIntValue);
  838.     }
  839.  
  840.     else if (LastToken == OP_OPEN_PAR)
  841.     {
  842.         ParseMathsExpression (MAX_PRECEDENCE);
  843.  
  844.         if (LastToken != OP_CLOSE_PAR)
  845.         {
  846.         ShellErrorMessage ("unmatched ()'s");
  847.         return;
  848.         }
  849.     }
  850.  
  851.     else if (LastToken == OP_QUESTION_MARK)
  852.     {
  853.         long    q = stack[StackPointer].val;
  854.  
  855.         if (!q)
  856.         JustParsing++;
  857.  
  858.         ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences - 1);
  859.  
  860.         if (!q)
  861.         JustParsing--;
  862.  
  863.         else
  864.         JustParsing++;
  865.  
  866.         ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences);
  867.  
  868.         if (q)
  869.         JustParsing--;
  870.  
  871.         ProcessOperator (OP_QUESTION_MARK);
  872.         continue;
  873.     }
  874.  
  875.     else
  876.     {
  877.         int        otok = LastToken;
  878.         int        onoeval = JustParsing;
  879.  
  880.         if (Operators[otok].Type == BOOL_A)
  881.         ProcessBinaryOperator (otok);
  882.  
  883.         ParseMathsExpression (Operators[otok].Precedences -
  884.                   (Operators[otok].Type != RIGHT_LEFT_A));
  885.         JustParsing = onoeval;
  886.         ProcessOperator (otok);
  887.         continue;
  888.     }
  889.  
  890.     LastToken = MathsLexicalAnalyser ();
  891.     }
  892. }
  893.  
  894. /*
  895.  * Decide on 'op=', 'opop' or 'op'
  896.  */
  897.  
  898. static int F_LOCAL DecideDoubleOperator (char op,
  899.                      int dequal,
  900.                      int equal,
  901.                          int twice,
  902.                      int single)
  903. {
  904.     RecogniseUnaryOperator = TRUE;
  905.  
  906.     if (*CStringp == op)
  907.     {
  908.     if (*(++CStringp) == CHAR_ASSIGN)
  909.     {
  910.         CStringp++;
  911.         return dequal;
  912.     }
  913.  
  914.     return twice;
  915.     }
  916.  
  917.     else if (*CStringp == CHAR_ASSIGN)
  918.     {
  919.     CStringp++;
  920.     return equal;
  921.     }
  922.  
  923.     return single;
  924. }
  925.  
  926. /*
  927.  * Decide on single operator 'op' or 'op='
  928.  */
  929.  
  930. static int F_LOCAL DecideSingleOperator (int equal, int single)
  931. {
  932.     RecogniseUnaryOperator = TRUE;
  933.  
  934.     if (*CStringp != CHAR_ASSIGN)
  935.     return single;
  936.  
  937.     CStringp++;
  938.     return equal;
  939. }
  940.  
  941. /*
  942.  * Handle +=, ++, + or -=, --, -
  943.  */
  944.  
  945. static int F_LOCAL DecideSignOperator (char sign, int pre_op, int post_op,
  946.                     int equals, int unary_op, int op)
  947. {
  948.     if ((*CStringp == sign) && (RecogniseUnaryOperator || !isalnum (*CStringp)))
  949.     {
  950.     CStringp++;
  951.     return RecogniseUnaryOperator ? pre_op : post_op;
  952.     }
  953.  
  954.     if (*CStringp == CHAR_ASSIGN)
  955.     {
  956.     RecogniseUnaryOperator = TRUE;
  957.     CStringp++;
  958.     return equals;
  959.     }
  960.  
  961.     return RecogniseUnaryOperator ? unary_op : op;
  962. }
  963.  
  964. /*
  965.  * Validate maths expression without the error message generated a
  966.  * command.  This forces the processing to drop down the stack rather than
  967.  * doing a deep-exit on error.
  968.  */
  969.  
  970. bool ValidMathsExpression (char *string, long *value)
  971. {
  972.     ErrorPoint     Save_ERP = e.ErrorReturnPoint;
  973.     bool    Save_EED = ExpansionErrorDetected;
  974.     bool    Result;
  975.  
  976. /* save the environment */
  977.  
  978.     e.ErrorReturnPoint = (ErrorPoint)NULL;
  979.     ExpansionErrorDetected = FALSE;
  980.  
  981. /* Validate the number */
  982.  
  983.     *value = EvaluateMathsExpression (string);
  984.     Result = ExpansionErrorDetected;
  985.  
  986. /* Restore environment */
  987.  
  988.     e.ErrorReturnPoint = Save_ERP;
  989.     ExpansionErrorDetected = Save_EED;
  990.     return Result;
  991. }
  992.  
  993. /*
  994.  * Extract a variable name and possible index
  995.  */
  996.  
  997. static char * F_LOCAL ExtractNameAndIndex (int s, int *index)
  998. {
  999.     long    IndValue;
  1000.     char    *Vp;
  1001.     char    *sp = StringCopy (ListOfVariableNames[s]);
  1002.  
  1003.     if (!GetVariableName (sp, &IndValue, &Vp, (bool *)NULL) || (*Vp))
  1004.     PrintErrorMessage (BasicErrorMessage, ListOfVariableNames[s],
  1005.                LIT_BadID);
  1006.  
  1007.     if (IndValue == -1)
  1008.     PrintErrorMessage (LIT_BadArray, ListOfVariableNames[s]);
  1009.  
  1010.     *index = (int)IndValue;
  1011.     return sp;
  1012. }
  1013.